package com.zjdiepu.www.security.client.encode.rsa;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.PublicKey;

import javax.crypto.Cipher;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zjdiepu.www.config.ClientConfig;
import com.zjdiepu.www.security.encode.base64.Base64;
import com.zjdiepu.www.security.encode.rsa.RsaEncrypt;
import com.zjdiepu.www.security.server.core.Partners;
/**
 * 类描述:RSA加解密 <br/>     
 * 项目名称:zjdiepu-client <br/> 
 * 类名称:ClientForServerRsaUtil<br/>     
 * 创建人:xiongxiaotun <br/> 
 * 创建时间:2017年8月16日 下午4:44:44  <br/>   
 * 修改人:xiongxiaotun <br/> 
 * 修改时间: 2017年8月16日 下午4:44:44   <br/>  
 * 修改备注:   <br/> 
 * @version V1.0   <br/>
 */
public class ClientRsaUtil {
	private static final Logger logger = LoggerFactory.getLogger(ClientRsaUtil.class);
	/**
     * RSA最大加密明文大小 512 / 8 = 64 - 11 = 53  1024 / 8 = 128 - 11 = 117
     */  
    private static final int MAX_ENCRYPT_BLOCK = (RsaEncrypt.KEY_SIZE / 8 ) - 11;  
      
    /** *//** 
     * RSA最大解密密文大小 512 / 8 = 64  1024 / 8 = 128
     */  
    private static final int MAX_DECRYPT_BLOCK = RsaEncrypt.KEY_SIZE / 8;  

    /** 
     * 公钥加密过程 
     *  
     * @param publicKey 
     *            公钥 
     * @param plainTextData 
     *            明文数据 
     * @return 密文
     */  
    public static String encrypt(String plainTextData, Partners partner) {
    	if(StringUtils.isBlank(plainTextData)) {
			return null;
		}
    	if(null == partner) {
			return null;
		}
    	//合作伙伴公钥解码
        PublicKey publicKey = RsaEncrypt.loadPublicKeyByStr(ClientConfig.getPartnerRsaPublicKey(partner));
        Cipher cipher = null;  
        try ( ByteArrayOutputStream out = new ByteArrayOutputStream(); ){  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
            byte[] data = plainTextData.getBytes("UTF-8");  
            int inputLen = data.length;  
            int offSet = 0;  
            byte[] cache;  
            int i = 0;  
            // 对数据分段加密  
            while (inputLen - offSet > 0) {  
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
                } else {  
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);  
                }  
                out.write(cache, 0, cache.length);  
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;  
            }  
            byte[] encryptedData = out.toByteArray();  
            return Base64.encode(encryptedData);
        } catch (Exception e) {  
        	logger.error("公钥加密过程:plainTextData:{},partner:{}.异常栈:{}", new String(plainTextData),partner.getCode(), e);
        } 
        return null;
    }  
	
  /**
	* 私钥解密
	* @param content 密文
	* @param privateKey 私钥
	* @param partner 合作伙伴
	* @return 明文
	*/
	public static String decrypt(String content, Partners partner){
		if(StringUtils.isBlank(content)) {
			return null;
		}
		//合作伙伴公钥加密
        PublicKey publicKey = RsaEncrypt.loadPublicKeyByStr(ClientConfig.getPartnerRsaPublicKey(partner));
        ByteArrayOutputStream writer;
		try {
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			//JSON对java String 类型会多出引号
			if(content.startsWith("\"")){
				content = content.substring(1);
			}
			if(content.endsWith("\"")) {
				content = content.substring(0, content.length() - 1);
			}
			byte[] decode = Base64.decode(content);
			InputStream ins = new ByteArrayInputStream(decode);
			writer = new ByteArrayOutputStream();
			//rsa解密的字节大小最多是128，将需要解密的内容，按128位拆开解密
			byte[] buf = new byte[MAX_DECRYPT_BLOCK];
			int bufl;

			while ((bufl = ins.read(buf)) != -1) {
			    byte[] block = null;

			    if (buf.length == bufl) {
			        block = buf;
			    } else {
			        block = new byte[bufl];
			        for (int i = 0; i < bufl; i++) {
			            block[i] = buf[i];
			        }
			    }

			    writer.write(cipher.doFinal(block));
			}
			return new String(writer.toByteArray(),"UTF-8");
		} catch (Exception e) {
			logger.error("私钥解密过程  :cipherData:{},partner:{}.异常栈:{}", content,partner.getCode(), e);
		}
		return null;
    }

}
